#
#   GameObjectManager.py
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; version 2 of the License.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   Copyright
#   Author: Nicholas F. Hoover
#   Contributors: Salvatore S. Gionfriddo
#   Created: 2007.06.20
#   Last Modified: 2007.07.10
#

import pygame, random
import GameObject
from EvilGreg import EvilGreg, DeadEvilGreg
from BasicKid import BasicKid
from FastKid import FastKid
from Flame import Flame
from PowerUp import PowerUp

class GameObjectManager(object):

    NUM_SOUNDS = 3
    (CRUNCH_SOUND,
     KID_DIE_SOUND,
     EG_EAT_SOUND) = range(NUM_SOUNDS)

    def __init__(self):
        self.evilGreg = EvilGreg()
        self.deadEG = DeadEvilGreg()
        self.baseBasicKid = BasicKid()
        self.baseFastKid = FastKid()
        self.kids = pygame.sprite.OrderedUpdates()
        self.baseFlame = Flame()
        self.flames = pygame.sprite.RenderPlain()
        self.basePowerUp = PowerUp(PowerUp.RIGHT)
        self.powerUps = pygame.sprite.OrderedUpdates()


    def linkAnimations(self, resourceManager, fps):
        self.evilGreg.linkAnimations(resourceManager,fps)
        self.deadEG.linkAnimations(resourceManager,fps)
        self.baseBasicKid.linkAnimations(resourceManager,fps)
        self.baseFastKid.linkAnimations(resourceManager,fps)
        self.baseFlame.linkAnimations(resourceManager,fps)
        self.basePowerUp.linkAnimations(resourceManager, fps)

    def linkSounds(self,resourceManager):
        self.evilGreg.linkSounds(resourceManager)
        self.deadEG.linkSounds(resourceManager)
        self.baseBasicKid.linkSounds(resourceManager)
        self.baseFastKid.linkSounds(resourceManager)
        self.baseFlame.linkSounds(resourceManager)
        self.sounds = range(self.NUM_SOUNDS)
        self.sounds[self.CRUNCH_SOUND]  = resourceManager.getSound('Kid_Crunch')
        self.sounds[self.KID_DIE_SOUND] = resourceManager.getSound('Kid_Die')
        self.sounds[self.EG_EAT_SOUND]  = resourceManager.getSound('EG_Eat')

    def reset(self):
        self.evilGreg.reset()
        self.kids.empty()
        self.run = True
        self.resetSpawners()
        self.powerUps.empty()
        self.flames.empty()

    def setSpawners(self, spawners):
        self.spawners = spawners
    def resetSpawners(self):
        if hasattr(self,'spawners'):
            for spawner in self.spawners:
                spawner.reset()
    def spawn(self):
        if hasattr(self,'spawners'):
            for spawner in self.spawners:
                spawner.spawn()
    def addSpawner(self, spawner):
        if hasattr(self, 'spawners'):
            self.spawners.append(spawner)
        else:
            self.spawners = [spawner]
        
    #update all the sprites, check for collisions and handle them, draw on the screen
    def update(self, screen):

        #add random kids on a timer
        self.spawn()
        
        self.powerUps.update()
        self.kids.update(self.evilGreg.rect)
        self.evilGreg.update()
        self.createFlame()
        self.flames.update()
        self.checkCollisions()

        self.powerUps.draw(screen)
        self.kids.draw(screen)
        screen.blit(self.evilGreg.image, self.evilGreg.rect)
        self.flames.draw(screen)
         
    def checkCollisions(self):
        self.checkPunch()
        self.checkKick()
        self.checkKidAttack()
        self.checkEvilGregEat()
        self.checkFlame()
        
    def checkPunch(self):
        if self.evilGreg.isActionActive(EvilGreg.PUNCH):
            punch = self.evilGreg.createPunchSprite()
            kills = self.hitKids(pygame.sprite.spritecollide(punch,self.kids,False), EvilGreg.PUNCH_DAMAGE)
            self.evilGreg.killsByPunch += kills

    def checkKick(self):
        if self.evilGreg.isActionActive(EvilGreg.KICK):
            kick = self.evilGreg.createKickSprite()
            kills = self.hitKids(pygame.sprite.spritecollide(kick,self.kids,False), EvilGreg.KICK_DAMAGE)
            self.evilGreg.killsByKick += kills
        
    def checkFlame(self):
        flameHitDict = pygame.sprite.groupcollide(self.flames, self.kids, False, False)
        for flame in flameHitDict:
            if flame.isActionActive(Flame.FLAME):
                kills = self.hitKids(flameHitDict[flame],EvilGreg.FLAME_DAMAGE)
                self.evilGreg.killsByFlame += kills

    def hitKids(self, kidList, totalDamage):
        kills = 0
        for kid in kidList[:]:
            if totalDamage > 0:
                self.sounds[self.CRUNCH_SOUND].play()
                
                if kid.health <= totalDamage:
                    totalDamage -= kid.health
                    kid.decHealth(kid.health)
                else:
                    kid.decHealth(totalDamage)
                    totalDamage = 0
                
                if not kid.isAlive():
                    self.addDeadKid(kid)
                    self.evilGreg.kills += 1
                    kills += 1
                    kid.kill()
                    self.sounds[self.KID_DIE_SOUND].play()
        return kills

    def checkEvilGregEat(self):
        if self.evilGreg.isActionActive(EvilGreg.EAT):
            eat = self.evilGreg.createEatSprite()
            self.eatPowerUps(pygame.sprite.spritecollide(eat, self.powerUps, False))
    
    def eatPowerUps(self, puList):
        for powerUp in puList[0:EvilGreg.MAX_POWERUPS_EAT]:
            if powerUp.isDeadKid():
                self.evilGreg.kidsEaten += 1
            self.sounds[self.EG_EAT_SOUND].play()
            for effect in powerUp.effects:
                self.evilGreg.addEffect(effect)
            powerUp.kill()

    def checkKidAttack(self):
        kids = pygame.sprite.spritecollide(self.evilGreg,self.kids,False)
        for kid in kids:
            if kid.isActionActive(BasicKid.BITE):
                kid.sounds[BasicKid.BITE].play()
                self.evilGreg.decHealth(BasicKid.BITE_DAMAGE)

    def createFlame(self):
        if self.evilGreg.isActionActive(EvilGreg.FLAME):
            flame = Flame()
            flame.animations = self.baseFlame.animations
            flame.sounds = self.baseFlame.sounds
            if self.evilGreg.facing == EvilGreg.RIGHT:
                flame.setPosition(self.evilGreg.rect.left + 50, self.evilGreg.rect.top + 30)
            else:
                flame.setPosition(self.evilGreg.rect.left - flame.rect.width + 10, self.evilGreg.rect.top + 30)
                flame.facing = Flame.LEFT
            flame.flame()
            self.flames.add(flame)
            flame.sounds[Flame.FLAME].play()

            
    def addDeadKid(self, kid):
        """Add a new DeadKid to the field basic on the killing of the given kid"""
        #MAD HAX follow, proceed with caution
        if kid.__class__ == BasicKid:
            powerUpType = PowerUp.DEAD_BASIC_KID
        elif kid.__class__ == FastKid:
            powerUpType = PowerUp.DEAD_FAST_KID
        else:
            raise Exception('Could not find Kid type:', kid.__class__)
        
        if kid.facing == kid.LEFT:
            facing = PowerUp.LEFT
        else:
            facing = PowerUp.RIGHT
            
        newDeadKid = PowerUp(facing, powerUpType)
        newDeadKid.animations = self.basePowerUp.animations
        newDeadKid.setPosition(kid.rect.left-10,kid.rect.top+20)
        self.powerUps.add(newDeadKid)
        self.powerUps._spritelist.sort(GameObject.gameObjectPosCompare)

    def addKid(self):
        newKid = BasicKid()
        baseKid = self.baseBasicKid
        self._addKid(newKid, baseKid)
        
    def addFastKid(self):
        newKid = FastKid()
        baseKid = self.baseFastKid
        self._addKid(newKid, baseKid)
    
    def _addKid(self, newKid, baseKid):
        (x,y) = self.getRandomEdgeCoords()
        newKid.animations = baseKid.animations
        newKid.sounds = baseKid.sounds
        newKid.setPosition(x,y)
        
        self.kids.add(newKid)
        self.kids._spritelist.sort(GameObject.gameObjectPosCompare)

    def getRandomEdgeCoords(self):
        xy_min = 0
        x_max = 800
        y_max = 600
        x = random.randrange(800)
        y = random.randrange(600)
        choices = [(x,xy_min), (x,y_max), (xy_min,y), (x_max,y)]
        (x,y) = random.choice(choices)
        return (x,y)
        
    def getRandomInternalCoords(self):
        x = random.randrange(20,780)
        y = random.randrange(20,580)
        return (x,y)
        
    def _addPowerUp(self, powerUpType):
        (x,y) = self.getRandomInternalCoords()
        newPowerUp = PowerUp(PowerUp.RIGHT, powerUpType)
        newPowerUp.animations = self.basePowerUp.animations
        newPowerUp.setPosition(x,y)
        self.powerUps.add(newPowerUp)
        self.powerUps._spritelist.sort(GameObject.gameObjectPosCompare)
    def addDrugs(self):
        self._addPowerUp(PowerUp.DRUGS)
    def addPizza(self):
        self._addPowerUp(PowerUp.PIZZA)
    def addIndian(self):
        self._addPowerUp(PowerUp.INDIAN)

    #this is a little bit #HACKS
    def killEG(self, screen):
        if self.evilGreg.facing == EvilGreg.LEFT:
            self.deadEG.facing = DeadEvilGreg.LEFT
        else: self.deadEG.facing = DeadEvilGreg.RIGHT
        self.deadEG.currentAnimation = DeadEvilGreg.DEAD + self.deadEG.facing
        self.deadEG.setPosition(self.evilGreg.rect.left, self.evilGreg.rect.bottom - 60)
        self.deadEG.update()
        
        self.powerUps.draw(screen)
        self.kids.draw(screen)
        screen.blit(self.deadEG.image, self.deadEG.rect)
        self.flames.draw(screen)
         
